#include<iostream>
#include <unistd.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include<arpa/inet.h>
#include <string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unordered_map>

#include"ThreadPool.hpp"
using namespace std;

#define BACKLOG 5
class pragm
{
public:
    int _sock;
    int _port;
    string _ip;
public:
    pragm(int sock,int port,string ip)
        :_sock(sock),
         _port(port),
         _ip(ip)
    {}
    ~pragm(){}

};
class Handler
{
public:
	Handler()
	{}
	~Handler()
	{}
	void operator()(int sock, std::string client_ip, int client_port)
	{
        unordered_map<string,string> dict;
        dict.insert(make_pair("space","空间"));
        dict.insert(make_pair("bule","蓝色"));

		char buffer[1024];
        string value;
		while (true){
			ssize_t size = read(sock, buffer, sizeof(buffer)-1);
			if (size > 0){ //读取成功
				buffer[size] = '\0';
				std::cout << client_ip << ":" << client_port << "# " << buffer << std::endl;

                string key=buffer;
                auto it=dict.find(key);
                if(it!=dict.end())
                {
                    value=it->second;
                }
                else
                {
                    value=key;
                }
				write(sock, value.c_str(), value.size());
			}
			else if (size == 0){ //对端关闭连接
				std::cout << client_ip << ":" << client_port << " close!" << std::endl;
				break;
			}
			else{ //读取失败
				std::cerr << sock << " read error!" << std::endl;
				break;
			}
		}
		close(sock); //归还文件描述符
		std::cout << client_ip << ":" << client_port << " service done!" << std::endl;
	}
};
class Task
{
public:
	Task()
	{}
	Task(int sock, std::string client_ip, int client_port)
		: _sock(sock)
		, _client_ip(client_ip)
		, _client_port(client_port)
	{}
	~Task()
	{}
	//任务处理函数
	void Run()
	{
	    _handler(_sock, _client_ip, _client_port); //调用仿函数
	}
private:
	int _sock; //套接字
	std::string _client_ip; //IP地址
	int _client_port; //端口号
	Handler _handler; //处理方法
};



class tcpServer
{
private:
    int _listen_sock;
    int _port;
    threadPool<Task>* _tp;
public:
    tcpServer(int port)
        :_listen_sock(-1),
         _port(port)
    {}
    ~tcpServer()
    {
        if(_listen_sock>0)
        {
            close(_listen_sock);
        }
    }
    void InitServer()
    {
        _listen_sock=socket(AF_INET,SOCK_STREAM,0);
        if(_listen_sock<0)
        {
            cout<<"socket create error"<<endl;
            exit(2);
        }
        cout<<"socket create success"<<endl;
        
        struct sockaddr_in local;
        memset(&local,'\0',sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;

        int f_bind=bind(_listen_sock,(struct sockaddr*)&local,sizeof(sockaddr));
        if(f_bind<0)
        {
            cout<<"bind error"<<endl;
            exit(3);
        }
        cout<<"bind success"<<endl;

        int f_listen=listen(_listen_sock,BACKLOG);
        if(f_listen<0)
        {
            cout<<"listen error"<<endl;
            exit(4);
        }
        cout<<"listen success"<<endl;
        _tp=new threadPool<Task>();
    }
    static void Service(int sock,string client_ip,int client_port)
    {
        char buffer[128];
        while(true)
        {
            ssize_t size=read(sock,buffer,sizeof(buffer)-1);
            if(size>0)
            {
                buffer[size]='\0';
                std::cout << "get a new link->" << sock << " [" << client_ip << "]:" << client_port <<"#"<<buffer<<std::endl;
                write(sock,buffer,sizeof(buffer)-1);

            }else if(size==0)
            {
                cout<<client_ip<<":"<<client_port<<"close!"<<endl;
                break;
            }else
            {
                cout<<sock<<"read error"<<endl;
            }
        }
        close(sock);
        cout<<client_ip<<":"<<client_port<<"service done!"<<endl;
    }
    static void* Handler(void* arg)
    {
        pthread_detach(pthread_self());

        pragm*p=(pragm*)arg;
        Service(p->_sock,p->_ip,p->_port);
        delete p;
        return nullptr;
    }
    void start()
    {
        _tp->ThreadPoolInit();
        while(true)
        {
            struct sockaddr_in peer;
            memset(&peer,'\0',sizeof(peer));
            socklen_t len=sizeof(peer);
            int sock=accept(_listen_sock,(struct sockaddr*)&peer,&len);
            if(sock<0)
            {
                cout<<"accept error,continue next"<<endl;
                continue;
            }
            string client_ip=inet_ntoa(peer.sin_addr);
            int client_port=ntohs(peer.sin_port);
            cout<<"get a new link->"<<sock<<"["<<client_ip<<"]"<<client_port<<endl;
            // pid_t id=fork();
            // if(id==0)
            // {
            //     close(_listen_sock);
            //     if(fork()>0)
            //     {
            //         exit(0);
            //     }
            //     Service(sock,client_ip,client_port);
            //     exit(0);
            // }
            // //处理请求
            // close(sock);
            // waitpid(id,nullptr,0);
            // pragm*p=new pragm(sock,client_port,client_ip);
            // pthread_t tid;
            // pthread_create(&tid,nullptr,Handler,p);
            Task task(sock,client_ip,client_port);
            _tp->Push(task);
        }
    }

};

void Usage(std::string proc)
{
	std::cout << "Usage: " << proc << " port" << std::endl;
}
int main(int argc, char* argv[])
{
	if (argc != 2){
		Usage(argv[0]);
		exit(1);
	}
	int port = atoi(argv[1]);
	tcpServer* svr = new tcpServer(port);
	svr->InitServer();
	svr->start();
	return 0;
}

